package com.bnz.search.service.impl;


import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.aggregations.*;
import co.elastic.clients.elasticsearch._types.query_dsl.MultiMatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;

import co.elastic.clients.elasticsearch._types.query_dsl.TermQuery;

import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;

import co.elastic.clients.elasticsearch.core.search.Highlight;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;


import com.alibaba.fastjson.JSON;
import com.bnz.search.entity.ItemEntity;
import com.bnz.search.entity.ItemVo;
import com.bnz.search.service.ItemSearchService;
import org.apache.commons.lang3.StringUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.*;


//@Service
public class ItemSearchServiceImpl4 implements ItemSearchService {
    @Autowired
    private ElasticsearchClient client;
    @Autowired
    private StringRedisTemplate redisTemplate;


    /**
     * 1. 进行各种查询
     *
     * @param vo
     * @return
     * @throws IOException
     */
    @Override
    public Map search(ItemVo vo) throws IOException {
        //new map
        Map resultMap = new HashMap();
        //根据参数进行查询--关键词
        if(vo != null){
            //定义查询到的商品列表
            List<ItemEntity> itemList = new ArrayList<>();
            //分类列表集合
            List<String> categoryList = new ArrayList<>();
             //如果不为null就进行查询。
            if(StringUtils.isNotBlank(vo.getKeywords())){
                //多字段匹配查询
                Query multiMatchQuery = MultiMatchQuery.of(m -> m.fields("title","brand","category").query(vo.getKeywords()))._toQuery();
                //高亮查询
                //无循序，前缀后缀，字段吧
                Highlight highlight = Highlight.of(h -> h.fields("title",f->f).preTags("<span style='color:red'>").postTags("</span>"));
                //对分类进行分组聚合查询
                Aggregation categoryAgg = Aggregation.of(a -> a.terms(t -> t.field("category")));
                //查询集合
                List<Query> queryList = new ArrayList<>();
                //分类查询
                if(StringUtils.isNotBlank(vo.getCategory())){
                    queryList.add(TermQuery.of(t -> t.field("category").value(vo.getCategory()))._toQuery());
                }
                //品牌查询
                if(StringUtils.isNotBlank(vo.getBrand())){
                    queryList.add(TermQuery.of(b -> b.value(vo.getBrand()).field("brand"))._toQuery());
                }
                //查询规格
                if(vo.getSpec() != null && vo.getSpec().size() > 0){
                    for (String s : vo.getSpec()) {
                        String[] split = s.split(":");      // 规格名字
                        System.out.println("split[0]  = " + split[0] + ",split[1] = " + split[1] );
                        queryList.add(TermQuery.of(sp -> sp.field("specMap." + split[0] + ".keyword").value(split[1]))._toQuery());
                    }
                }
                queryList.add(multiMatchQuery);
                SearchRequest request = SearchRequest.of(s -> s
                        .index("item")
                        .query(q -> q
                                .bool(b -> b
                                                .filter(queryList)
                                        // .filter(TermQuery.of(t -> t.field("category").value(vo.getCategory()))._toQuery())

                                ))
                        .aggregations("category-agg",categoryAgg)
                        .highlight(highlight));




                //查询结果
                SearchResponse<ItemEntity> searchResponse = client.search(request, ItemEntity.class);


                //得到命中查询的结果（不包含分组聚合查询,包含高亮查询）
                HitsMetadata<ItemEntity> resultHits = searchResponse.hits();
                //总记录数
                long total = resultHits.total().value();
                System.out.println("total = " + total);


                List<Hit<ItemEntity>> hits = resultHits.hits();
                //遍历查询结果
                for (Hit<ItemEntity> hit : hits) {
                    //得到结果的源数据
                    ItemEntity itemEntity = hit.source();
                    //高亮数据
                    Map<String, List<String>> stringListMap = hit.highlight();
                    if(!CollectionUtils.isEmpty(stringListMap)){
                        //2高亮数据
                        List<String> list = stringListMap.get("title");
                        //取得高亮数据
                        if(!CollectionUtils.isEmpty(list)){
                            itemEntity.setTitle(list.get(0));
                            itemList.add(itemEntity);
                        }
                    }
                }

                //聚合查询的结果
                //聚合查询
                Map<String, Aggregate> aggregations = searchResponse.aggregations();
                //得到指定名称的聚合查询
                StringTermsAggregate sterms = aggregations.get("category-agg").sterms();
                //批量查询的数组
                List<StringTermsBucket> termsBuckets = sterms.buckets().array();
                //数组放到分类中
                for (StringTermsBucket termsBucket : termsBuckets) {
                    //聚合查询的结果
                    String key = termsBucket.key();
                    //结果放到list中
                    categoryList.add(key);
                }
            }

            //判断分类是否有值
            //根据分类查询品牌及规格列表
            String category = "";
            if(!CollectionUtils.isEmpty(categoryList)){
                if(StringUtils.isNotBlank(vo.getCategory())){
                    category = vo.getCategory();
                }else{
                    category = categoryList.get(0);
                }
            }
            //在redis中查询品牌及规格列表
            Map brandAndSpecMap = findBrandAndSpecList(category);
            //将品牌及规格列表放到大map
            resultMap.putAll(brandAndSpecMap);
            //将商品列表放如resultMap
            resultMap.put("itemList",itemList);
            //将分类列表放到 分类map中
            resultMap.put("categoryList",categoryList);

            System.out.println("resultMap = " + resultMap);
        }
        return resultMap;
    }

    /**
     * 根据分类名称在redis中查询规格及品牌列表
     * @param category
     * @return
     */
    private Map findBrandAndSpecList(String category) {
        //根据分类查模板id
        BoundHashOperations<String, String, String> boundHashOperations = redisTemplate.boundHashOps("itemCatList");
        String typeId = boundHashOperations.get(category);
        if(typeId == null){
            typeId = "";
        }
        //根据模板id查品牌规格
        String brandList = (String) redisTemplate.boundHashOps("brandList").get(typeId);
        List<Map> brands = JSON.parseArray(StringUtils.isNotBlank(brandList) ? brandList : "[]",Map.class);
        String specList = (String) redisTemplate.boundHashOps("specList").get(typeId);
        List<Map> specs = JSON.parseArray(StringUtils.isNotBlank(specList) ? specList : "[]",Map.class);
        //构造返回map
        Map map = new HashMap();
        //BrandEntity
        //SpecificationEntity品牌及规格列表放到map中
        map.put("specList",specs);
        map.put("brandList",brands);
        return map;

    }
}